package iterator;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import constants.NumberConstants;
import data.DataManager;
import data.Environment;
import data.Game;
import data.Player;

public class IterativeRanker {
	private Map<Player, IterativeRank> playerRanks;
	private IterativeRank [] ranks;
	private Game [] games;
	private DataManager manager;
	private IterativeBalance iterativeBalance;
	private boolean printFirst = true;
	public static boolean last = false;
	public IterativeRanker (DataManager manager){
		this.manager = manager;
		Player [] players = manager.getPlayers();
		this.ranks = new IterativeRank [players.length];
		this.games = manager.getGames();
		playerRanks = new HashMap<Player, IterativeRank>();
		for (int i = 0; i < players.length; i++) {
			ranks [i] = new IterativeRank(players[i]);
			playerRanks.put(players[i], ranks[i]);
		}
		this.iterativeBalance = new TieIterativeBalance(players, this);
	}
	public void start(){
		iterationCounter = 0;
		iterate();
//		System.out.println("Required " + iterationCounter + " iterations.");
	}
	private int iterationCounter;
	
	private void iterate() {
		boolean hasChanged = true;
		while (hasChanged) {
			iterationCounter++;
			for (int i = 0; i < games.length; i++) {
				applyGame(games[i]);
			}
			iterativeBalance.applyBalance();
			hasChanged = applyRanks();
			if (iterationCounter>NumberConstants.MAX_ITERATIONS){
				System.out.println("Reached breaking point");
				return;
			}
			printFirst = false;
		}
		last = true;
		for (int i = 0; i < games.length; i++) {
			applyGame(games[i]);
		}
		iterativeBalance.applyBalance();
	}
	private void applyGame(Game game){
		Player player1 = game.getPlayer1();
		Player player2 = game.getPlayer2();
		if (game.getPlayer1score()>game.getPlayer2score())
			applyWin(player1, player2,game.getEnvironment());
		else if (game.getPlayer2score()>game.getPlayer1score())
			applyWin(player2, player1,game.getEnvironment());
		else
			applyTie(player1, player2,game.getEnvironment());
	}
	public void applyWin(Player winner, Player loser, Environment environemnt){
		IterativeRank winnerRank = playerRanks.get(winner);
		IterativeRank loserRank = playerRanks.get(loser);
		double weight = NumberConstants.environmentWeight.get(environemnt);
		int gamesAgainstOpponent = manager.getNumberOfGamesBetweenPlayers(winner, loser);
		int totalGames = manager.getNumberOfGames(winner);
//		if (gamesAgainstOpponent<6)
//			weight = weight*(0.5 +(0.1*gamesAgainstOpponent));
		weight *= Math.sqrt(totalGames) * Math.sqrt(gamesAgainstOpponent);
		winnerRank.gainPoints(loserRank, NumberConstants.STARTING_RANK*playerRanks.size(),  weight);
	}
	public void applyTie(Player player1, Player player2, Environment environemnt){
		applyTie(player1, player2, NumberConstants.environmentWeight.get(environemnt));
	}
	public void applyTie(Player player1, Player player2, double weight){
		playerRanks.get(player1).transferPointsTie(playerRanks.get(player2), weight);
	}
	private boolean applyRanks(){
		boolean hasChanged = false;
		for (int i = 0; i < ranks.length; i++) {
			if (ranks[i].applyRank())
				hasChanged = true;
		}
		return hasChanged;
	}

	public void printRanks(){
		double totalRank = 0;;
		IterativeRank [] ranksOnly = playerRanks.values().toArray(new IterativeRank [playerRanks.size()]);
		Arrays.sort(ranksOnly);
		for (int i = 0; i < ranksOnly.length; i++) {
			totalRank += ranksOnly[i].getRank();
			System.out.println(ranksOnly[i]);
		}
		System.out.println(totalRank+" ");
	}

}
